use anyhow::Context;
use std::fs;
use std::num::ParseIntError;
use thiserror::Error;
use tracing::info;

#[derive(Debug, Error)]
pub enum MyError {
    #[error("I/O error")]
    Io(#[from] std::io::Error),

    #[error("Parse error")]
    Parse(#[from] std::num::ParseIntError),

    #[error("Serialize error:{0}")]
    Serialize(#[from] serde_json::error::Error),

    #[error("Custom error:{0}")]
    Custom(String),

    // #[error("Error:{a},{b:?},{c:?},{d:?}")]
    // BigError{
    //     a:String,
    //     b:Vec<String>,
    //     c:[u8;64],
    //     d:u64,
    // }
    #[error("Custom error:{0:?}")]
    BigError(Box<BigError>),
}

#[allow(unused)]
#[derive(Debug)]
pub struct BigError {
    a: String,
    b: Vec<String>,
    c: [u8; 64],
    d: u64,
}

//
// impl From<std::io::Error> for MyError {
//     fn from(e: std::io::Error) -> Self {
//         MyError::Custom(e.to_string())
//     }
// }

#[allow(unused)]
fn main1() -> Result<(), anyhow::Error> {
    println!("size of MyError is {}", size_of::<MyError>());
    println!("size of anyhow error is {}", size_of::<anyhow::Error>());
    println!("size of io Error is {}", size_of::<std::io::Error>());
    println!("size of ParseIntError is {}", size_of::<ParseIntError>());
    println!(
        "size of serde_json error is {}",
        size_of::<serde_json::Error>()
    );
    println!("size of string  is {}", size_of::<String>());
    let filename = "test.txt";
    let _fd = fs::File::open(filename).with_context(|| format!("failed to open {filename}"))?;

    fail_with_error()?;
    Ok(())
}

fn main() -> Result<(), MyError> {
    tracing_subscriber::fmt::init();
    let number_of_yaks = 3;
    info!(number_of_yaks, "preparing to shave yaks");

    Ok(())
}

#[allow(unused)]
fn fail_with_error() -> Result<(), MyError> {
    Err(MyError::Custom("Something went wrong".to_string()))
}
